Add cargo test
authorTim Carey-Smith <tim@spork.in>
Thu, 26 Jun 2014 22:14:31 +0000 (15:14 -0700)
committerTim Carey-Smith <tim@spork.in>
Thu, 26 Jun 2014 23:47:27 +0000 (16:47 -0700)
21 files changed:
Makefile
src/bin/cargo-build.rs
src/bin/cargo-test.rs [new file with mode: 0644]
src/cargo/core/dependency.rs
src/cargo/core/manifest.rs
src/cargo/core/mod.rs
src/cargo/lib.rs
src/cargo/ops/cargo_compile.rs
src/cargo/ops/cargo_rustc.rs
src/cargo/ops/mod.rs
src/cargo/sources/git/source.rs
src/cargo/util/hex.rs [new file with mode: 0644]
src/cargo/util/mod.rs
src/cargo/util/process_builder.rs
src/cargo/util/toml.rs
tests/support/mod.rs
tests/test_cargo_compile.rs
tests/test_cargo_compile_git_deps.rs
tests/test_cargo_compile_path_deps.rs
tests/test_cargo_test.rs [new file with mode: 0644]
tests/tests.rs

index 2e852de1fa777ee6ee6b6f585d75851e675bd3d4..dac214192549657fa4be1264fe58a8e79dd6db51 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ BINS = cargo \
             cargo-rustc \
             cargo-verify-project \
             cargo-git-checkout \
+                cargo-test \
 
 SRC = $(shell find src -name '*.rs' -not -path 'src/bin*')
 
index 8a0f065811c25e3c71efa01368c7c73a095f3ad2..c3d3c96fef82dae868f9421dbae5983b9cb469d8 100644 (file)
@@ -48,7 +48,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
 
     let update = options.update_remotes;
 
-    ops::compile(&root, update, shell).map(|_| None).map_err(|err| {
+    ops::compile(&root, update, "compile", shell).map(|_| None).map_err(|err| {
         CliError::from_boxed(err, 101)
     })
 }
diff --git a/src/bin/cargo-test.rs b/src/bin/cargo-test.rs
new file mode 100644 (file)
index 0000000..8849b2d
--- /dev/null
@@ -0,0 +1,60 @@
+#![crate_id="cargo-test"]
+#![feature(phase)]
+
+#[phase(plugin, link)]
+extern crate cargo;
+extern crate serialize;
+
+#[phase(plugin, link)]
+extern crate hammer;
+
+use std::os;
+use std::io::fs;
+
+use cargo::ops;
+use cargo::{execute_main_without_stdin};
+use cargo::core::{MultiShell};
+use cargo::util;
+use cargo::util::{CliResult, CliError};
+use cargo::util::important_paths::find_project;
+
+#[deriving(PartialEq,Clone,Decodable)]
+struct Options {
+    manifest_path: Option<String>,
+    rest: Vec<String>
+}
+
+hammer_config!(Options "Run the package's test suite")
+
+fn main() {
+    execute_main_without_stdin(execute);
+}
+
+fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
+    let root = match options.manifest_path {
+        Some(path) => Path::new(path),
+        None => try!(find_project(os::getcwd(), "Cargo.toml")
+                    .map(|path| path.join("Cargo.toml"))
+                    .map_err(|_| {
+                        CliError::new("Could not find Cargo.toml in this \
+                                       directory or any parent directory",
+                                      102)
+                    }))
+    };
+
+    try!(ops::compile(&root, false, "test", shell).map(|_| None::<()>).map_err(|err| {
+        CliError::from_boxed(err, 101)
+    }));
+
+    let test_dir = root.dir_path().join("target").join("tests");
+
+    let mut walk = try!(fs::walk_dir(&test_dir).map_err(|e| {
+        CliError::from_error(e, 1)
+    }));
+
+    for file in walk {
+        try!(util::process(file).exec().map_err(|e| CliError::from_boxed(e.box_error(), 1)));
+    }
+
+    Ok(None)
+}
index 687e4911642a886ed1d8d13168d856eb2380e389..6e4c8b25ff8f415845f9171ee7115f2eb018ba0c 100644 (file)
@@ -1,4 +1,3 @@
-use semver::Version;
 use core::{VersionReq,SourceId};
 use util::CargoResult;
 
@@ -10,18 +9,9 @@ pub struct Dependency {
 }
 
 impl Dependency {
-    pub fn new(name: &str, req: &VersionReq,
-               namespace: &SourceId) -> Dependency {
-        Dependency {
-            name: name.to_str(),
-            namespace: namespace.clone(),
-            req: req.clone()
-        }
-    }
-
     pub fn parse(name: &str, version: Option<&str>,
-                 namespace: &SourceId) -> CargoResult<Dependency> {
-
+                 namespace: &SourceId) -> CargoResult<Dependency>
+    {
         let version = match version {
             Some(v) => try!(VersionReq::parse(v)),
             None => VersionReq::any()
@@ -34,15 +24,6 @@ impl Dependency {
         })
     }
 
-    pub fn exact(name: &str, version: &Version,
-                 namespace: &SourceId) -> Dependency {
-        Dependency {
-            name: name.to_str(),
-            namespace: namespace.clone(),
-            req: VersionReq::exact(version)
-        }
-    }
-
     pub fn get_version_req<'a>(&'a self) -> &'a VersionReq {
         &self.req
     }
index 21982438d1b874bbfdfaf602a53cb4f737e9983b..f9b4c0e1840c8eabf4b21483d7aefd1b4cc80adb 100644 (file)
@@ -58,7 +58,7 @@ impl<E, S: Encoder<E>> Encodable<S, E> for Manifest {
     }
 }
 
-#[deriving(Show,Clone,PartialEq,Encodable)]
+#[deriving(Show, Clone, PartialEq, Hash, Encodable)]
 pub enum LibKind {
     Lib,
     Rlib,
@@ -92,17 +92,64 @@ impl LibKind {
     }
 }
 
-#[deriving(Show,Clone,PartialEq,Encodable)]
+#[deriving(Show, Clone, Hash, PartialEq, Encodable)]
 pub enum TargetKind {
     LibTarget(Vec<LibKind>),
     BinTarget
 }
 
-#[deriving(Clone,PartialEq)]
+#[deriving(Clone, Hash, PartialEq)]
+pub struct Profile {
+    env: String, // compile, test, dev, bench, etc.
+    opt_level: uint,
+    debug: bool,
+    test: bool
+}
+
+impl Profile {
+    pub fn default(env: &str) -> Profile {
+        Profile {
+            env: env.to_str(), // run in the default environment only
+            opt_level: 0,
+            debug: true,
+            test: false // whether or not to pass --test
+        }
+    }
+
+    pub fn is_compile(&self) -> bool {
+        self.env.as_slice() == "compile"
+    }
+
+    pub fn is_test(&self) -> bool {
+        self.test
+    }
+
+    pub fn get_env<'a>(&'a self) -> &'a str {
+        self.env.as_slice()
+    }
+
+    pub fn opt_level(mut self, level: uint) -> Profile {
+        self.opt_level = level;
+        self
+    }
+
+    pub fn debug(mut self, debug: bool) -> Profile {
+        self.debug = debug;
+        self
+    }
+
+    pub fn test(mut self, test: bool) -> Profile {
+        self.test = test;
+        self
+    }
+}
+
+#[deriving(Clone, Hash, PartialEq)]
 pub struct Target {
     kind: TargetKind,
     name: String,
-    path: Path
+    path: Path,
+    profile: Profile
 }
 
 #[deriving(Encodable)]
@@ -191,19 +238,21 @@ impl Manifest {
 
 impl Target {
     pub fn lib_target(name: &str, crate_targets: Vec<LibKind>,
-                      path: &Path) -> Target {
+                      path: &Path, profile: &Profile) -> Target {
         Target {
             kind: LibTarget(crate_targets),
             name: name.to_str(),
-            path: path.clone()
+            path: path.clone(),
+            profile: profile.clone()
         }
     }
 
-    pub fn bin_target(name: &str, path: &Path) -> Target {
+    pub fn bin_target(name: &str, path: &Path, profile: &Profile) -> Target {
         Target {
             kind: BinTarget,
             name: name.to_str(),
-            path: path.clone()
+            path: path.clone(),
+            profile: profile.clone()
         }
     }
 
@@ -225,6 +274,10 @@ impl Target {
         }
     }
 
+    pub fn get_profile<'a>(&'a self) -> &'a Profile {
+        &self.profile
+    }
+
     pub fn rustc_crate_types(&self) -> Vec<&'static str> {
         match self.kind {
             LibTarget(ref kinds) => {
index b14bbd6e259fb96707f45e70756feb8d93ecffe0..23716f6be8c185a812ccecf1817284eacb3efca7 100644 (file)
@@ -6,6 +6,7 @@ pub use self::manifest::{
     Manifest,
     Target,
     TargetKind,
+    Profile
 };
 
 pub use self::package::{
@@ -36,7 +37,10 @@ pub use self::shell::{
     ShellConfig
 };
 
-pub use self::dependency::Dependency;
+pub use self::dependency::{
+    Dependency
+};
+
 pub use self::version_req::VersionReq;
 
 pub mod errors;
index ccae60e3a8777d7eb47766991288bfb1f9d630b3..32a45e48b0f7174a43e68bc5533687dcd6b0cb07 100644 (file)
@@ -39,9 +39,18 @@ macro_rules! some(
     )
 )
 
+// Added so that the try! macro below can refer to cargo::util, while
+// other external importers of this macro can use it as well.
+//
+// "Hygiene strikes again" - @acrichton
+mod cargo {
+    pub use super::util;
+}
+
+#[macro_export]
 macro_rules! try (
     ($expr:expr) => ({
-        use util::CargoError;
+        use cargo::util::CargoError;
         match $expr.map_err(|err| err.to_error()) {
             Ok(val) => val,
             Err(err) => return Err(err)
index 308a1146a7605e4fa5970219d294384ded203eaa..9e8b4d4b053165b3f879616a1c913e0e4a5f9c6e 100644 (file)
 
 use std::os;
 use util::config::{Config, ConfigValue};
-use core::{MultiShell, Source, SourceId, PackageSet, resolver};
+use core::{MultiShell, Source, SourceId, PackageSet, Target, resolver};
 use core::registry::PackageRegistry;
 use ops;
 use sources::{PathSource};
 use util::{CargoResult, Wrap, config, internal, human};
 
-pub fn compile(manifest_path: &Path, update: bool, shell: &mut MultiShell) -> CargoResult<()> {
+pub fn compile(manifest_path: &Path, update: bool,
+               env: &str, shell: &mut MultiShell) -> CargoResult<()>
+{
     log!(4, "compile; manifest-path={}", manifest_path.display());
 
     let mut source = PathSource::for_path(&manifest_path.dir_path());
@@ -60,8 +62,13 @@ pub fn compile(manifest_path: &Path, update: bool, shell: &mut MultiShell) -> Ca
 
     debug!("packages={}", packages);
 
+    let targets = package.get_targets().iter().filter(|target| {
+        target.get_profile().get_env() == env
+    }).collect::<Vec<&Target>>();
+
     let mut config = try!(Config::new(shell, update));
-    try!(ops::compile_packages(&package, &PackageSet::new(packages.as_slice()), &mut config));
+    try!(ops::compile_targets(targets.as_slice(), &package,
+         &PackageSet::new(packages.as_slice()), &mut config));
 
     Ok(())
 }
index 3357ff886c9daf3fde9cd512bb632a253a5ff7da..3411f5306f22dad68a85ce1d6957be9e1e9bd339 100644 (file)
@@ -2,6 +2,8 @@ use std::os::args;
 use std::io;
 use std::io::{File, IoError};
 use std::str;
+use std::hash::sip::SipHasher;
+use std::hash::Hasher;
 
 use core::{Package, PackageSet, Target};
 use util;
@@ -19,13 +21,14 @@ struct Context<'a, 'b> {
     config: &'b mut Config<'b>
 }
 
-pub fn compile_packages<'a>(pkg: &Package, deps: &PackageSet,
-                        config: &'a mut Config<'a>) -> CargoResult<()> {
+pub fn compile_targets<'a>(targets: &[&Target], pkg: &Package, deps: &PackageSet,
+                           config: &'a mut Config<'a>) -> CargoResult<()> {
 
-    debug!("compile_packages; pkg={}; deps={}", pkg, deps);
+    debug!("compile_targets; targets={}; pkg={}; deps={}", targets, pkg, deps);
 
     let target_dir = pkg.get_absolute_target_dir();
     let deps_target_dir = target_dir.join("deps");
+    let tests_target_dir = target_dir.join("tests");
 
     let output = try!(util::process("rustc").arg("-v").exec_with_output());
     let rustc_version = str::from_utf8(output.output.as_slice()).unwrap();
@@ -41,6 +44,10 @@ pub fn compile_packages<'a>(pkg: &Package, deps: &PackageSet,
         internal(format!("Couldn't create the directory for dependencies for {} at {}",
                  pkg.get_name(), deps_target_dir.display()))));
 
+    try!(mk_target(&tests_target_dir).chain_error(||
+        internal(format!("Couldn't create the directory for tests for {} at {}",
+                 pkg.get_name(), tests_target_dir.display()))));
+
     let mut cx = Context {
         dest: &deps_target_dir,
         deps_dir: &deps_target_dir,
@@ -52,19 +59,29 @@ pub fn compile_packages<'a>(pkg: &Package, deps: &PackageSet,
 
     // Traverse the dependencies in topological order
     for dep in try!(topsort(deps)).iter() {
-        try!(compile_pkg(dep, &mut cx));
+        let targets = dep.get_targets().iter().filter(|target| {
+            // Only compile lib targets for dependencies
+            target.is_lib() && target.get_profile().is_compile()
+        }).collect::<Vec<&Target>>();
+
+        try!(compile(targets.as_slice(), dep, &mut cx));
     }
 
     cx.primary = true;
     cx.dest = &target_dir;
-    try!(compile_pkg(pkg, &mut cx));
+
+    try!(compile(targets, pkg, &mut cx));
 
     Ok(())
 }
 
-fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
+fn compile(targets: &[&Target], pkg: &Package, cx: &mut Context) -> CargoResult<()> {
     debug!("compile_pkg; pkg={}; targets={}", pkg, pkg.get_targets());
 
+    if targets.is_empty() {
+        return Ok(());
+    }
+
     // First check to see if this package is fresh.
     //
     // Note that we're compiling things in topological order, so if nothing has
@@ -74,10 +91,12 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
     //
     // This is not quite accurate, we should only trigger forceful
     // recompilations for downstream dependencies of ourselves, not everyone
-    // compiled afterwards.
+    // compiled afterwards.a
+    //
+    // TODO: Figure out how this works with targets
     let fingerprint_loc = cx.dest.join(format!(".{}.fingerprint",
                                                pkg.get_name()));
-    let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, cx));
+    let (is_fresh, fingerprint) = try!(is_fresh(pkg, &fingerprint_loc, cx, targets));
     if !cx.compiled_anything && is_fresh {
         try!(cx.config.shell().status("Fresh", pkg));
         return Ok(())
@@ -88,6 +107,7 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
     // command if one is present.
     try!(cx.config.shell().status("Compiling", pkg));
 
+    // TODO: Should this be on the target or the package?
     match pkg.get_manifest().get_build() {
         Some(cmd) => try!(compile_custom(pkg, cmd, cx)),
         None => {}
@@ -95,11 +115,8 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
 
     // After the custom command has run, execute rustc for all targets of our
     // package.
-    for target in pkg.get_targets().iter() {
-        // Only compile lib targets for dependencies
-        if cx.primary || target.is_lib() {
-            try!(rustc(&pkg.get_root(), target, cx))
-        }
+    for &target in targets.iter() {
+        try!(rustc(&pkg.get_root(), target, cx));
     }
 
     // Now that everything has successfully compiled, write our new fingerprint
@@ -111,13 +128,18 @@ fn compile_pkg(pkg: &Package, cx: &mut Context) -> CargoResult<()> {
 }
 
 fn is_fresh(dep: &Package, loc: &Path,
-            cx: &mut Context) -> CargoResult<(bool, String)> {
-    let new_fingerprint = format!("{}{}", cx.rustc_version,
+            cx: &mut Context, targets: &[&Target]) -> CargoResult<(bool, String)>
+{
+    let new_pkg_fingerprint = format!("{}{}", cx.rustc_version,
                                   try!(dep.get_fingerprint(cx.config)));
+
+    let new_fingerprint = fingerprint(new_pkg_fingerprint, hash_targets(targets));
+
     let mut file = match File::open(loc) {
         Ok(file) => file,
         Err(..) => return Ok((false, new_fingerprint)),
     };
+
     let old_fingerprint = try!(file.read_to_str());
 
     log!(5, "old fingerprint: {}", old_fingerprint);
@@ -126,6 +148,17 @@ fn is_fresh(dep: &Package, loc: &Path,
     Ok((old_fingerprint == new_fingerprint, new_fingerprint))
 }
 
+fn hash_targets(targets: &[&Target]) -> u64 {
+    let hasher = SipHasher::new_with_keys(0,0);
+    let targets = targets.iter().map(|t| (*t).clone()).collect::<Vec<Target>>();
+    hasher.hash(&targets)
+}
+
+fn fingerprint(package: String, profiles: u64) -> String {
+    let hasher = SipHasher::new_with_keys(0,0);
+    util::to_hex(hasher.hash(&(package, profiles)))
+}
+
 fn mk_target(target: &Path) -> Result<(), IoError> {
     io::fs::mkdir_recursive(target, io::UserRWX)
 }
@@ -170,6 +203,7 @@ fn prepare_rustc(root: &Path, target: &Target, crate_types: Vec<&str>,
     build_base_args(&mut args, target, crate_types, cx);
     build_deps_args(&mut args, cx);
 
+
     util::process("rustc")
         .cwd(root.clone())
         .args(args.as_slice())
@@ -184,8 +218,16 @@ fn build_base_args(into: &mut Args, target: &Target, crate_types: Vec<&str>,
         into.push("--crate-type".to_str());
         into.push(crate_type.to_str());
     }
+
+    let mut out = cx.dest.clone();
+
+    if target.get_profile().is_test() {
+        into.push("--test".to_str());
+        out = out.join("tests");
+    }
+
     into.push("--out-dir".to_str());
-    into.push(cx.dest.display().to_str());
+    into.push(out.display().to_str());
 }
 
 fn build_deps_args(dst: &mut Args, cx: &Context) {
index 456a56ee7daffb369ff5861ad5e9293aa72c723a..785f77fad9338476aeabb92cb4d5753d9d2c3e71 100644 (file)
@@ -1,6 +1,6 @@
 pub use self::cargo_compile::compile;
 pub use self::cargo_read_manifest::{read_manifest,read_package,read_packages};
-pub use self::cargo_rustc::compile_packages;
+pub use self::cargo_rustc::compile_targets;
 
 mod cargo_compile;
 mod cargo_read_manifest;
index 97462af20852a75cc20039f2fa142023b9378024..c126fe2b4d8a026533d45d993576661345b86d86 100644 (file)
@@ -2,13 +2,11 @@ use std::fmt::{Show,Formatter};
 use std::fmt;
 use std::hash::Hasher;
 use std::hash::sip::SipHasher;
-use std::io::MemWriter;
 use std::str;
-use serialize::hex::ToHex;
 
 use core::source::{Source, SourceId, GitKind, Location, Remote, Local};
 use core::{Package,PackageId,Summary};
-use util::{CargoResult,Config};
+use util::{CargoResult, Config, to_hex};
 use sources::PathSource;
 use sources::git::utils::{GitReference,GitRemote,Master,Other};
 
@@ -81,12 +79,6 @@ fn ident(location: &Location) -> String {
     format!("{}-{}", ident, to_hex(hasher.hash(&location.to_str())))
 }
 
-fn to_hex(num: u64) -> String {
-    let mut writer = MemWriter::with_capacity(8);
-    writer.write_le_u64(num).unwrap(); // this should never fail
-    writer.get_ref().to_hex()
-}
-
 impl<'a, 'b> Show for GitSource<'a, 'b> {
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
         try!(write!(f, "git repo at {}", self.remote.get_location()));
diff --git a/src/cargo/util/hex.rs b/src/cargo/util/hex.rs
new file mode 100644 (file)
index 0000000..7512ece
--- /dev/null
@@ -0,0 +1,10 @@
+use std::io::MemWriter;
+
+use serialize::hex::ToHex;
+
+pub fn to_hex(num: u64) -> String {
+    let mut writer = MemWriter::with_capacity(8);
+    writer.write_le_u64(num).unwrap(); // this should never fail
+    writer.get_ref().to_hex()
+}
+
index a17294cfdfce6d5eb1ee5ef39e8c3cbb0bfe0a43..5cc0ccb348c8cf6e0e19d49d6b04f260eeb68160 100644 (file)
@@ -5,6 +5,7 @@ pub use self::errors::{CargoResult, CargoError, BoxError, ChainError, CliResult}
 pub use self::errors::{CliError, FromError, ProcessError};
 pub use self::errors::{process_error, internal_error, internal, human};
 pub use self::paths::realpath;
+pub use self::hex::to_hex;
 
 pub mod graph;
 pub mod process_builder;
@@ -14,3 +15,4 @@ pub mod result;
 pub mod toml;
 pub mod paths;
 pub mod errors;
+pub mod hex;
index 1eb7a5f23ccb95c48616f32e922bf275f040e3d3..772109404d39c34d0c8aa5a109d3e92af0a1bcac 100644 (file)
@@ -51,7 +51,7 @@ impl ProcessBuilder {
 
     pub fn extra_path(mut self, path: Path) -> ProcessBuilder {
         // For now, just convert to a string, but we should do something better
-        self.path.push(path.display().to_str());
+        self.path.unshift(path.display().to_str());
         self
     }
 
index e9352a1400eda4a2a91420080faf46c2d0537977..d8d904330ff921cf86a0cd072e0dfa9b119cc502 100644 (file)
@@ -5,7 +5,7 @@ use toml;
 use url;
 
 use core::{SourceId, GitKind};
-use core::manifest::{LibKind, Lib};
+use core::manifest::{LibKind, Lib, Profile};
 use core::{Summary, Manifest, Target, Dependency, PackageId};
 use core::source::{Location, Local, Remote};
 use util::{CargoResult, Require, human};
@@ -66,6 +66,7 @@ pub enum TomlDependency {
     DetailedDep(DetailedTomlDependency)
 }
 
+
 #[deriving(Encodable,Decodable,PartialEq,Clone,Show)]
 pub struct DetailedTomlDependency {
     version: Option<String>,
@@ -184,28 +185,46 @@ impl TomlManifest {
 struct TomlTarget {
     name: String,
     crate_type: Option<Vec<String>>,
-    path: Option<String>
+    path: Option<String>,
+    test: Option<bool>
 }
 
 fn normalize(lib: Option<&[TomlLibTarget]>,
              bin: Option<&[TomlBinTarget]>) -> Vec<Target> {
     log!(4, "normalizing toml targets; lib={}; bin={}", lib, bin);
 
+    fn target_profiles(target: &TomlTarget) -> Vec<Profile> {
+        let mut ret = vec!(Profile::default("compile"));
+
+        match target.test {
+            Some(true) | None => ret.push(Profile::default("test").test(true)),
+            _ => {}
+        };
+
+        ret
+    }
+
     fn lib_targets(dst: &mut Vec<Target>, libs: &[TomlLibTarget]) {
         let l = &libs[0];
         let path = l.path.clone().unwrap_or_else(|| format!("src/{}.rs", l.name));
         let crate_types = l.crate_type.clone().and_then(|kinds| {
             LibKind::from_strs(kinds).ok()
         }).unwrap_or_else(|| vec!(Lib));
-        dst.push(Target::lib_target(l.name.as_slice(), crate_types,
-                                    &Path::new(path)));
+
+        for profile in target_profiles(l).iter() {
+            dst.push(Target::lib_target(l.name.as_slice(), crate_types.clone(),
+                                        &Path::new(path.as_slice()), profile));
+        }
     }
 
     fn bin_targets(dst: &mut Vec<Target>, bins: &[TomlBinTarget],
                    default: |&TomlBinTarget| -> String) {
         for bin in bins.iter() {
             let path = bin.path.clone().unwrap_or_else(|| default(bin));
-            dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path)));
+
+            for profile in target_profiles(bin).iter() {
+                dst.push(Target::bin_target(bin.name.as_slice(), &Path::new(path.as_slice()), profile));
+            }
         }
     }
 
index 8b3c296e001a62c2ec7693fd570cec566a337481..39f5eef86a452ac41fbd1dd74e34d7873c68e860 100644 (file)
@@ -357,3 +357,21 @@ impl<T> Tap for T {
 pub fn escape_path(p: &Path) -> String {
     p.display().to_str().as_slice().replace("\\", "\\\\")
 }
+
+pub fn basic_bin_manifest(name: &str) -> String {
+    format!(r#"
+        [project]
+
+        name = "{}"
+        version = "0.5.0"
+        authors = ["wycats@example.com"]
+
+        [[bin]]
+
+        name = "{}"
+    "#, name, name)
+}
+
+pub static COMPILING: &'static str = "   Compiling";
+pub static FRESH:     &'static str = "       Fresh";
+pub static UPDATING:  &'static str = "    Updating";
index 91cb04807d7d0efadd9ca8ee39143910ead9ee67..168603d22f9df4aa03250f18bf21a2bf59fff4ed 100644 (file)
@@ -2,7 +2,8 @@ use std::io::fs;
 use std::os;
 use std::path;
 
-use support::{ResultTest, project, execs, main_file, escape_path};
+use support::{ResultTest, project, execs, main_file, escape_path, basic_bin_manifest};
+use support::COMPILING;
 use hamcrest::{assert_that, existing_file};
 use cargo;
 use cargo::util::{process, realpath};
@@ -10,22 +11,6 @@ use cargo::util::{process, realpath};
 fn setup() {
 }
 
-static COMPILING: &'static str = "   Compiling";
-
-fn basic_bin_manifest(name: &str) -> String {
-    format!(r#"
-        [project]
-
-        name = "{}"
-        version = "0.5.0"
-        authors = ["wycats@example.com"]
-
-        [[bin]]
-
-        name = "{}"
-    "#, name, name)
-}
-
 test!(cargo_compile_simple {
     let p = project("foo")
         .file("Cargo.toml", basic_bin_manifest("foo").as_slice())
index 052bc7e6e17a00982214949467bd82f80d6b4563..4af43c06c604065a887e43a6a9604df40b3151ba 100644 (file)
@@ -2,14 +2,11 @@ use std::io::File;
 
 use support::{ProjectBuilder, ResultTest, project, execs, main_file, paths};
 use support::{escape_path, cargo_dir};
+use support::{COMPILING, FRESH, UPDATING};
 use hamcrest::{assert_that,existing_file};
 use cargo;
 use cargo::util::{ProcessError, process};
 
-static COMPILING: &'static str = "   Compiling";
-static FRESH:     &'static str = "       Fresh";
-static UPDATING:  &'static str = "    Updating";
-
 fn setup() {
 }
 
index 635808eb16564a938fe0219e5a5642db87129602..25bbf0df9d89a8d38b8b004212504489b0262e9a 100644 (file)
@@ -2,6 +2,7 @@ use std::io::File;
 use std::io::timer;
 
 use support::{ResultTest, project, execs, main_file, escape_path, cargo_dir};
+use support::{COMPILING, FRESH};
 use hamcrest::{assert_that, existing_file};
 use cargo;
 use cargo::util::{process};
@@ -9,9 +10,6 @@ use cargo::util::{process};
 fn setup() {
 }
 
-static COMPILING: &'static str = "   Compiling";
-static FRESH:     &'static str = "       Fresh";
-
 test!(cargo_compile_with_nested_deps_shorthand {
     let p = project("foo")
         .file("Cargo.toml", r#"
diff --git a/tests/test_cargo_test.rs b/tests/test_cargo_test.rs
new file mode 100644 (file)
index 0000000..ad47932
--- /dev/null
@@ -0,0 +1,40 @@
+use support::{project, execs, basic_bin_manifest, COMPILING};
+use hamcrest::{assert_that, existing_file};
+use cargo::util::process;
+
+fn setup() {}
+
+test!(cargo_test_simple {
+    let p = project("foo")
+        .file("Cargo.toml", basic_bin_manifest("foo").as_slice())
+        .file("src/foo.rs", r#"
+            fn hello() -> &'static str {
+                "hello"
+            }
+
+            pub fn main() {
+                println!("{}", hello())
+            }
+
+            #[test]
+            fn test_hello() {
+                assert_eq!(hello(), "hello")
+            }"#);
+
+    assert_that(p.cargo_process("cargo-build"), execs());
+    assert_that(&p.bin("foo"), existing_file());
+
+    assert_that(
+        process(p.bin("foo")),
+        execs().with_stdout("hello\n"));
+
+    assert_that(p.cargo_process("cargo-test"),
+        execs().with_stdout(format!("{} foo v0.5.0 (file:{})\n\n\
+                                    running 1 test\n\
+                                    test test_hello ... ok\n\n\
+                                    test result: ok. 1 passed; 0 failed; \
+                                    0 ignored; 0 measured\n\n",
+                                    COMPILING, p.root().display())));
+    
+    assert_that(&p.bin("tests/foo"), existing_file());
+})
index 1e99363fc1a0fe5a17f6970dc849f2c509c96ed6..6dd3bb2802267706167a7ca6268fae465c3544d5 100644 (file)
@@ -23,4 +23,5 @@ macro_rules! test(
 mod test_cargo_compile;
 mod test_cargo_compile_git_deps;
 mod test_cargo_compile_path_deps;
+mod test_cargo_test;
 mod test_shell;